using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Text.Json;

namespace SeataNet.Core.Discovery.Nacos
{
    /// <summary>
    /// Nacos配置提供程序
    /// </summary>
    public class NacosConfigurationProvider : ConfigurationProvider, IDisposable
    {
        private readonly NacosConfigurationSource _source;
        private readonly ILogger<NacosConfigurationProvider> _logger;
        private readonly INacosConfigService _nacosConfigService;
        private readonly ConcurrentDictionary<string, string> _configKeys;
        private bool _disposed;

        public NacosConfigurationProvider(
            NacosConfigurationSource source,
            ILogger<NacosConfigurationProvider> logger,
            INacosConfigService nacosConfigService)
        {
            _source = source;
            _logger = logger;
            _nacosConfigService = nacosConfigService;
            _configKeys = new ConcurrentDictionary<string, string>();
        }

        public override void Load()
        {
            LoadAsync().GetAwaiter().GetResult();
        }

        private async Task LoadAsync()
        {
            try
            {
                foreach (var dataId in _source.DataIds)
                {
                    await LoadConfigAsync(dataId, _source.Group);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "加载Nacos配置失败");

                if (_source.Optional)
                {
                    return;
                }

                throw;
            }
        }

        private async Task LoadConfigAsync(string dataId, string? group)
        {
            try
            {
                var config = await _nacosConfigService.GetConfigAsync(dataId, group);

                if (string.IsNullOrEmpty(config))
                {
                    _logger.LogWarning($"配置为空: {dataId}");
                    return;
                }

                ParseConfig(dataId, config);

                // 添加监听器以支持动态刷新
                if (_source.ReloadOnChange)
                {
                    await _nacosConfigService.AddListenerAsync(dataId, newConfig =>
                    {
                        _logger.LogInformation($"配置已更新: {dataId}");
                        ParseConfig(dataId, newConfig);
                        OnReload();
                    }, group);
                }

                _logger.LogInformation($"加载配置成功: {dataId}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"加载配置失败: {dataId}");

                if (!_source.Optional)
                {
                    throw;
                }
            }
        }

        private void ParseConfig(string dataId, string config)
        {
            try
            {
                // 根据配置格式解析
                if (dataId.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
                {
                    ParseJsonConfig(config);
                }
                else if (dataId.EndsWith(".properties", StringComparison.OrdinalIgnoreCase))
                {
                    ParsePropertiesConfig(config);
                }
                else if (dataId.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) ||
                         dataId.EndsWith(".yml", StringComparison.OrdinalIgnoreCase))
                {
                    // YAML解析需要额外的库，这里简化处理
                    _logger.LogWarning($"YAML格式暂不支持: {dataId}");
                }
                else
                {
                    // 默认当作Properties格式
                    ParsePropertiesConfig(config);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"解析配置失败: {dataId}");
            }
        }

        private void ParseJsonConfig(string config)
        {
            var jsonDoc = JsonDocument.Parse(config);
            ParseJsonElement(string.Empty, jsonDoc.RootElement);
        }

        private void ParseJsonElement(string prefix, JsonElement element)
        {
            switch (element.ValueKind)
            {
                case JsonValueKind.Object:
                    foreach (var property in element.EnumerateObject())
                    {
                        var key = string.IsNullOrEmpty(prefix)
                            ? property.Name
                            : $"{prefix}:{property.Name}";
                        ParseJsonElement(key, property.Value);
                    }
                    break;

                case JsonValueKind.Array:
                    var index = 0;
                    foreach (var item in element.EnumerateArray())
                    {
                        ParseJsonElement($"{prefix}:{index}", item);
                        index++;
                    }
                    break;

                default:
                    var value = element.ToString();
                    Set(prefix, value);
                    _configKeys[prefix] = value;
                    break;
            }
        }

        private void ParsePropertiesConfig(string config)
        {
            var lines = config.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var line in lines)
            {
                var trimmedLine = line.Trim();

                // 跳过注释和空行
                if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith("#") || trimmedLine.StartsWith("!"))
                {
                    continue;
                }

                var separatorIndex = trimmedLine.IndexOf('=');
                if (separatorIndex == -1)
                {
                    separatorIndex = trimmedLine.IndexOf(':');
                }

                if (separatorIndex > 0)
                {
                    var key = trimmedLine.Substring(0, separatorIndex).Trim();
                    var value = trimmedLine.Substring(separatorIndex + 1).Trim();

                    // 转换为配置键格式 (a.b.c -> a:b:c)
                    key = key.Replace('.', ':');

                    Set(key, value);
                    _configKeys[key] = value;
                }
            }
        }

        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            _disposed = true;

            // 移除所有监听器
            foreach (var dataId in _source.DataIds)
            {
                _ = _nacosConfigService.RemoveListenerAsync(dataId, _source.Group);
            }
        }
    }

    /// <summary>
    /// Nacos配置源
    /// </summary>
    public class NacosConfigurationSource : IConfigurationSource
    {
        /// <summary>
        /// 数据ID列表
        /// </summary>
        public List<string> DataIds { get; set; } = new List<string>();

        /// <summary>
        /// 分组名称
        /// </summary>
        public string? Group { get; set; }

        /// <summary>
        /// 是否可选
        /// </summary>
        public bool Optional { get; set; } = true;

        /// <summary>
        /// 是否在配置变更时重新加载
        /// </summary>
        public bool ReloadOnChange { get; set; } = true;

        /// <summary>
        /// Nacos配置服务
        /// </summary>
        public INacosConfigService? NacosConfigService { get; set; }

        /// <summary>
        /// 日志工厂
        /// </summary>
        public ILoggerFactory? LoggerFactory { get; set; }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            if (NacosConfigService == null)
            {
                throw new InvalidOperationException("NacosConfigService未配置");
            }

            var logger = LoggerFactory?.CreateLogger<NacosConfigurationProvider>()
                         ?? throw new InvalidOperationException("LoggerFactory未配置");

            return new NacosConfigurationProvider(this, logger, NacosConfigService);
        }
    }

    /// <summary>
    /// Nacos配置构建器扩展
    /// </summary>
    public static class NacosConfigurationExtensions
    {
        /// <summary>
        /// 添加Nacos配置源
        /// </summary>
        public static IConfigurationBuilder AddNacosConfiguration(
            this IConfigurationBuilder builder,
            INacosConfigService nacosConfigService,
            ILoggerFactory loggerFactory,
            Action<NacosConfigurationSource> configureSource)
        {
            var source = new NacosConfigurationSource
            {
                NacosConfigService = nacosConfigService,
                LoggerFactory = loggerFactory
            };

            configureSource(source);
            builder.Add(source);

            return builder;
        }

        /// <summary>
        /// 添加Nacos配置源（简化版本）
        /// </summary>
        public static IConfigurationBuilder AddNacosConfiguration(
            this IConfigurationBuilder builder,
            INacosConfigService nacosConfigService,
            ILoggerFactory loggerFactory,
            string dataId,
            string? group = null,
            bool optional = true,
            bool reloadOnChange = true)
        {
            return builder.AddNacosConfiguration(nacosConfigService, loggerFactory, source =>
            {
                source.DataIds.Add(dataId);
                source.Group = group;
                source.Optional = optional;
                source.ReloadOnChange = reloadOnChange;
            });
        }

        /// <summary>
        /// 添加多个Nacos配置源
        /// </summary>
        public static IConfigurationBuilder AddNacosConfiguration(
            this IConfigurationBuilder builder,
            INacosConfigService nacosConfigService,
            ILoggerFactory loggerFactory,
            IEnumerable<string> dataIds,
            string? group = null,
            bool optional = true,
            bool reloadOnChange = true)
        {
            return builder.AddNacosConfiguration(nacosConfigService, loggerFactory, source =>
            {
                source.DataIds.AddRange(dataIds);
                source.Group = group;
                source.Optional = optional;
                source.ReloadOnChange = reloadOnChange;
            });
        }
    }
}
